<?php
/**
 * Created by PhpStorm.
 * User: eValor
 * Date: 2019-03-20
 * Time: 16:57
 */

namespace App\GameService;

use App\WebSocket\WsBase;
use App\Utility\BaseEnum;
use App\Common\AuthCommon;
use App\Common\BaseComm;
use App\Enum\CardEnum;
use App\Model\GameType;
use App\Utility\RedisTools;
use Swoole\Timer;
use App\GameService\games\PlayHelp;
use App\Common\GameCommon;
use App\Common\PlayCommon;
use App\Enum\SysEnum;

/**
 * 百人游戏类(百人牛牛，百人二八)
 * 
 */
class Gamehund extends WsBase
{
    
    protected $allowGameIds = [105];
    
    /**
     * 开始百人牛牛类游戏入口
     *
     * @return boolean
     */
    public function play(){
        $loginFd = $this->paramsBean->getFd();
        $data = $this->paramsBean->getData(true);
        $gameOObject = $this->paramsBean->getGameObject();
        $userid = FALSE;
        
        //TODO 登录验证
        $playerInfo = $this->LoginPlayUser($userid);
        if (!$playerInfo || $userid <= 0 ) { return FALSE; }
        
        BaseEnum::Logger('实例化：整体 (getGameObject)---playNewGame >>>' . json_encode($gameOObject), 'user-login');
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        if (! $gameRId) {
            $this->ResError(BaseEnum::MSG_0XF2, "游戏类型参数丢失");
            return true;
        }
        $steps = CardEnum::GAME_BRNN_STEP;
        $seatEmpty = ['seat1'=>0,'seat2'=>0,'seat3'=>0,'seat4'=>0];
        $mainInfo = ["name"=> '10***8',"sex"=> 1,'head_id'=> 2,"points"=> 0];
        $lastResult = ["gstart"=>1,"gameNo"=> null,"status" => 0,"player"=> null,"mainInfo"=> $mainInfo,"roomInfo"=>null,"lists"=>null];
        $roomSeatLimits = FALSE; //房间每个位置限红
        
        // 获取在线的游戏列表数据；
        try {
            $gameModel = new GameType();
            $gRoomInfo = $gameModel->getGameRoomDetail($gameRId); // 获取房间详细参数
            $gameID = isset($gRoomInfo["gameId"]) ? intval($gRoomInfo["gameId"]) : 0;
            $gameName = isset($gRoomInfo["gpKey"]) ? $gRoomInfo["gpKey"] : "";
            $roomLastPots = isset($gRoomInfo["smallPoints"]) ? floatval($gRoomInfo["smallPoints"]) : 0;         // 房间的携带分要求；
            $roomEveryPots = isset($gRoomInfo["everyPoints"]) ? floatval($gRoomInfo["everyPoints"]) : 0;        // 房间底分
            
            //TODO 判断是否开放这个游戏
            if($gameID >0 && $this -> pullGameStatus($gameID,$playerInfo,FALSE) === FALSE){
                $this->ResError(BaseEnum::MSG_0XF5,"该游戏暂未开放，请重试", SysEnum::RETURN_MSG_LEVEL_2);           //重新刷新
                return TRUE;
            }
            if (empty($gRoomInfo) || $gameID <= 0 || !in_array($gameID, $this->allowGameIds,TRUE)) {
                $this->ResError(BaseEnum::MSG_0XF6, "获取房间信息异常",SysEnum::RETURN_MSG_LEVEL_1);
                return true;
            }
            
            //生成筹码
            $selectChips = GameCommon::getRoomsChips($gameRId,$roomEveryPots);
            
            //房间位置限红值
            $roomSeatLimits = GameCommon::getRoomsLimitBets($gameRId,$roomEveryPots);
            
            
            $username = isset($playerInfo["name"]) ? $playerInfo["name"] : "";
            $login_points = isset($playerInfo["points"]) ? floatval($playerInfo["points"]) : 0;
            
            // 是否准入分
            if ($login_points <= 0 || $login_points < $roomLastPots || $roomEveryPots <= 0) {
                $this->ResError(BaseEnum::MSG_0XF8, "玩家游戏分达不到房间最低标准，退出房间!!",SysEnum::RETURN_MSG_LEVEL_1);
                return TRUE;
            }
            // 写入玩家信息
            $newWj = array(
                "uid" => $userid,
                "lineCode" => $playerInfo['lineCode'] ?? "",                                            // 玩家代理标记
                "isNation" => isset($playerInfo['isNation']) ? intval($playerInfo['isNation']) : 0,     // 玩家身份信息
                "agentId" => isset($playerInfo['recUid']) ? intval($playerInfo['recUid']) : 0,          // 代理用户ID
                "sex" => isset($playerInfo['gender']) ? intval($playerInfo['gender']) : 0,              // 性别
                "head_id" => isset($playerInfo['head_url']) ? intval($playerInfo['head_url']) : 0,      // 头像
                "fd" => $loginFd,
                "points" => $login_points,
                "notBetCount" => 0
            );
            $newWj["fullName"] = $username;
            $newWj["name"] = BaseComm::hiddenUserName($username); 
            
            //TODO  房间内在线玩家列表（加入）
            $wjList = BaseComm::distMemoryPlayer($gameRId,FALSE,null,TRUE);
            if (!$wjList) { $wjList = []; }
            $wjList[$userid] = $newWj;
            
            //TODO  把机器人数据放入玩家列表中
            $robotUser = PlayCommon::getHundRobotUsers($gameID,$gRoomInfo,NULL);
            if (!empty($robotUser)) {
                foreach ($robotUser as $robotone){
                    $oneUid = isset($robotone['uid']) ? intval($robotone['uid']) : 0 ;
                    if(!empty($wjList) && $oneUid >0 && !array_key_exists($oneUid, $wjList)){ $wjList[$oneUid] = $robotone; }
                }
            }
            BaseComm::distMemoryPlayer($gameRId ,TRUE,$wjList,TRUE);     //更新玩家列表
            
            //TODO 前20人排名
            /* $frontList = $wjList;
            @array_multisort(array_column($frontList,'points'),SORT_DESC,$frontList);
            if(isset($frontList) && !empty($frontList) && sizeof($frontList) > 20){ $frontList = array_slice($frontList, 0,20); } //取前二十名玩家信息 */
            
            
            //TODO 开奖结果走势数据推到前端
            $historydata = [];
            $historyWins = PlayHelp::getInstance()->getResultLog($gameRId,'history');
            if(!empty($historyWins)){
                foreach ($historyWins as $r => $oneivs){ $historydata[] = ["key"=>$r,"data"=> $oneivs]; }
            }
            
            //TODO  加入房间成功后就删掉当前用户在房间列表的操作；
            $allUserFds = BaseComm::distMemoryFjListUser($gameID,FALSE);
            if (!empty($allUserFds) && isset($allUserFds[$userid])) {
                unset($allUserFds[$userid]);
                BaseComm::distMemoryFjListUser($gameID,TRUE,$allUserFds);   //TODO　写入房间列表FD 
            }
            
            //TODO 游戏房间（首次进来 ｜正在进行中）
            $fjInfo = BaseComm::distMemoryRooms($gameRId,FALSE);
            $fjStatus = isset($fjInfo['fjStatus']) ? intval($fjInfo['fjStatus']) : 0 ; 
            $roomSays = array('gameId' => $gameRId,"everyPoints"=>$roomEveryPots,'smallPoints' => $roomLastPots,"chips"=> $selectChips,"history" => $historydata);
            
            
            
            $allWeis = []; 
            
            //正在游戏的房间号
            if (!isset($fjInfo) || empty($fjInfo)){
                $gameNo = BaseComm::getRoomUnioxNo($gameRId);               //生成房间编号
                BaseComm::gameLogger($gameNo,"百人牛牛　游戏开始启动  ->  玩家{$username}");
                
                //初始化空位置数据
                for ($j = 1; $j <= 4; $j++) {
                    $setk = "seat".$j;
                    $limits = isset($roomSeatLimits[$setk]) ? $roomSeatLimits[$setk] : FALSE;             //每个位置还要加下下注限红数据
                    $allWeis[] = ["seatNo"=> $j,"total" => 0, "min"=> $limits['min'] ?? 0,"max"=> $limits['max'] ?? 0];
                }
                $gameInfo = array("step" => '',"isCanBet" => 0,"seats"=> $allWeis,"seatCards" => []);
                $fjInfo = array(                                    //组装房间的状态信息;
                    "isOpen"    => 1,
                    "gameId"    => $gameID,
                    'grid'      => $gameRId,
                    "gameNo"    => $gameNo,
                    "fjStatus"  => -1,
                    'create' => time(),
                    "mutdotts"  => $seatEmpty,
                    'list' => [],
                );
                $allfdkey = SysEnum::USER_PLAY_FDMAP_KEY;
                RedisTools::Pool_hSet($allfdkey, $userid , json_encode([$gameNo,$gameRId]));  //缓存玩家最近的房间号；
                
                
                //房间内的数据结构
                BaseComm::distMemoryRooms($gameRId,TRUE,$fjInfo);
                //游戏开始(asycStartGame)
                if (!$gameOObject || empty($gameOObject) || (!empty($gameOObject) && isset($gameOObject -> baseGameName) && $gameOObject -> baseGameName != $gameName)) {
                    $gameOObject = BaseEnum::getClassObject($gameName, false);           // 创建对象；
                    BaseEnum::Logger('实例化为空：新实例化一个操作；-->>>' . json_encode(['gName'=> $gameName,"obj"=> $gameOObject]), 'user-login');
                }
                if (!empty($gameOObject)) {
                    BaseEnum::Logger("开始进入互动：Games-(play)-getClassObject，[{$gameName}]---->>>" . json_encode($gameOObject), 'user-login');
                    if (! empty($gameOObject) && method_exists($gameOObject, "asycStartGame")) {
                        
                        // 启动游戏操作
                        $gameOObject->setGameStatus("P-" . CardEnum::GAME_STEP_0); // 设置游戏状态；
                        BaseEnum::Logger('实例化对象：' . json_encode($gameOObject), 'user-login');
                        BaseEnum::Logger("开始进入互动：Games-(play)-getClassObject，[{$gameName}]---->>>" . $fjInfo['gameNo'], 'user-login');
                        
                        Timer::after(1000,function() use($gameNo,$gameRId,$gRoomInfo,$gameOObject){
                            $gameOObject -> asycStartGame($gameNo,$gameRId, $gRoomInfo);   //房间ID
                        });
                    }
                } else {
                    BaseEnum::Logger("互动失败：Games-(play)-getClassObject，[{$gameName}]----失败!!!!" . json_encode($gameOObject), 'user-login');
                }
                $lastResult["gstart"] = 1;
                $lastResult["gameNo"] = $gameNo;
                $lastResult['roomInfo'] = $roomSays;
                unset($newWj['notBetCount']);
                $lastResult['player'] = $newWj ;
                $lastResult['lists'] = $gameInfo;    
                if (!empty($loginFd)) { // 登录玩家通知：
                    $this->ResOK($lastResult,"玩家进入房间成功");
                }
                
            }else if(isset($fjInfo['gameNo']) && $fjStatus >= 0 ){
                
                $newGameNo = $fjInfo['gameNo'];
                //开局后  玩家再进入就是直接显示游戏数据；
                $lastResult["gstart"] = 1;
                $lastResult["status"] = $fjStatus ;
                $lastResult["gameNo"] = $newGameNo;
                $lastResult['roomInfo'] = $roomSays;
                unset($newWj['notBetCount']);
                $lastResult['player'] = $newWj;
                BaseComm::gameLogger($newGameNo,"百人牛牛　加入新玩家  ->  {$username}");
                
                //TODO  桌面下注情况
                $stepName = isset($steps[$fjStatus]) ? $steps[$fjStatus] : '';
                $gameInfo = array("step" => $stepName,"isCanBet" => 0,"seats"=> [],"seatCards" => []);
                $allWeis = [];
                if ($fjStatus >= 0) {
                    $allSes = (isset($fjInfo['mutdotts']) && !empty($fjInfo['mutdotts'])) ? $fjInfo['mutdotts'] :$seatEmpty ;
                    foreach ($allSes as $set => $setmoney){
                        $limits = isset($roomSeatLimits[$set]) ? $roomSeatLimits[$set] : FALSE;             //每个位置还要加下下注限红数据
                        $allWeis[] = ["seatNo"=> intval(substr($set,-1)),"total" => $setmoney, "min"=> $limits['min'] ?? 0,"max"=> $limits['max'] ?? 0];
                    }
                    if ($fjStatus == CardEnum::BR_GAME_STEP_3) {
                        $gameInfo['isCanBet'] = 1 ;                 //牌的数据；
                    }
                    if ($fjStatus > 0 && in_array($fjStatus, array(CardEnum::BR_GAME_STEP_5,CardEnum::BR_GAME_STEP_4),TRUE)) {
                        $newCards = PlayHelp::getInstance()-> getRoomCards($newGameNo);  //每个位置的发牌数据;
                        $gameInfo['seatCards'] = $this->parseGameCards($gameID,$gameRId,$newCards,$gRoomInfo);
                    }
                    //TODO 牌位上下注总数清零
                    if ($fjStatus == CardEnum::BR_GAME_STEP_6 && !empty($allWeis)) {
                        foreach ($allWeis as &$onelis) $onelis['total'] = 0; 
                    }
                    $gameInfo['seats'] = $allWeis;                  //座位信息
                }
                $lastResult['lists'] = $gameInfo;
                $this->ResOK($lastResult,"游戏进行中[{$stepName}]");  //正常游戏中(观望状态)；
            }
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：玩家上桌失败[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
        }
        return true;
    }
    
    
    //解析牌数据格式；
    protected function parseGameCards($gameID,$gameRId=0,$newCards = FALSE,$roomDetail = FALSE) {
        $zjObj = FALSE; // {"p_fd":15,"seatNo":0,"cards":[ 2,18,34,50,33],"userId":10002,"mainFlag":1}
        $xjList = [];
        //闲家列表  {"1":{"p_fd":14,"seatNo":1,"cards":[4,20,36,52,49],"userId":10001,"mainFlag":0}}
        foreach ($newCards as $seat => $setcard){
            $oneobj = ["seatNo"=> $seat,"cards"=> $setcard ?? FALSE, "userId"=> 0,"mainFlag"=> 0];
            if ($seat == 0) {
                $oneobj['mainFlag'] = 1;
                $zjObj = $oneobj;
            }else{
                $xjList[$seat] = $oneobj;
            }
        }
        //结算调用 
        $result = BaseComm::dealCards('BRNN',$zjObj,$xjList,$roomDetail);
        $result = !empty($result) ? array_values($result): FALSE ;
        return $result;
    }
    

    
    /**
     * TODO 玩家前20名的数据
     */
    public function fronts() {
        $data = $this->paramsBean->getData(true);
        $gameOObject = $this->paramsBean->getGameObject();
        BaseEnum::Logger('实例化：整体 (fronts)---fronts >>>' . json_encode($gameOObject), 'user-login');
        $gameRId = isset($data['gameRoomId']) ? intval($data['gameRoomId']) : 0;
        
        
        $userid = FALSE;
        
        //TODO 登录验证
        $playerInfo = $this->LoginPlayUser($userid);
        if (!$playerInfo || $userid <= 0 ) { return FALSE; }
        
        if (!$gameRId) {
            $this->ResError(BaseEnum::MSG_0XF2, "参数丢失");
            return true;
        }
        
        
        
        $userLists = [];
        try {
            //TODO 前20人排名:
            $frontList = BaseComm::distMemoryPlayer($gameRId,FALSE,null,TRUE);
            $myponts = !empty($frontList) ? array_column($frontList,'points'): FALSE;
            if(!empty($frontList) && !empty($myponts)){
                @array_multisort($myponts,SORT_DESC,$frontList);
                if(isset($frontList) && !empty($frontList) && sizeof($frontList) > 20){ $frontList = array_slice($frontList, 0,20); } //取前二十名玩家信息
                
                //20个玩家信息列表
                foreach ($frontList as $oneplay){
                    $userLists[] = ['uid'=>@$oneplay['uid'],'head_id'=>@$oneplay['head_id'],'name'=> @$oneplay['name'],'points'=> @$oneplay['points'],'sex' => @$oneplay['sex'] ];
                }
            }
            
            $this->ResOK($userLists,"成功");
            return TRUE;
        } catch (\Throwable $e) {
            BaseEnum::Logger("抛出异常：[code={$e->getCode()}]---msg==>" . $e->getMessage(), 'user-login');
        }
        return false;
    }
    
}